Original Authors: Belinda Phipson, Anna Trigos, Matt Ritchie, Maria Doyle, Harriet Dashnow, Charity Law Based on the course RNAseq analysis in R delivered on May 11/12th 2016

Before starting this section, we will make sure we have all the relevant objects from the Differential Expression analysis present.

suppressPackageStartupMessages(library(edgeR))
load("Robjects/DE.Rdata")

Overview

  • Visualising DE results
  • Getting annotation
  • Retrieving gene models
  • Exporting browser traecks
  • Visualising results with respect to genomic location

Adding annotation and saving the results

We have a list of significantly differentially expressed genes, but the only annotation we can see is the Entrez Gene ID, which is not very informative.

results <- as.data.frame(topTags(lrt.BvsL,n = Inf))
results

edgeR provides a function plotSmear that allows us to visualise the results of a DE analysis. In a similar manner to the MA-plot for microarray data, this plot shows the log-fold change against log-counts per million, with DE genes highlighted:

summary(de <- decideTestsDGE(lrt.BvsL))
   [,1]
-1 2404
0  9583
1  1322
detags <- rownames(dgeObj)[as.logical(de)]
plotSmear(lrt.BvsL, de.tags=detags)

However, on such a plot it would be nice to add labels to highlight the genes with most evidence for being DE, or our favourite genes. To perform such a task we need to map between the identifiers we have in the edgeR output and more familiar names.

There are a number of ways to add annotation, but we will demonstrate how to do this using the org.Mm.eg.db package. This package is one of several organism-level packages which are re-built every 6 months. These packages are listed on the annotation section of the Bioconductor, and are installed in the same way as regular Bioconductor packages. An alternative approach is to use biomaRt, an interface to the BioMart resource. BioMart is much more comprehensive, but the organism package fit better into the Bioconductor workflow.

source("http://www.bioconductor.org/biocLite.R")
biocLite("org.Mm.eg.db")
# For Human
biocLite("org.Hs.eg.db")

The packages are larger in size that Bioconductor software pacakges, but essentially they are databases that can be used to make offline queries.

library(org.Mm.eg.db)
Loading required package: AnnotationDbi
Loading required package: stats4
Loading required package: BiocGenerics
Loading required package: parallel

Attaching package: ‘BiocGenerics’

The following objects are masked from ‘package:parallel’:

    clusterApply, clusterApplyLB, clusterCall, clusterEvalQ, clusterExport, clusterMap,
    parApply, parCapply, parLapply, parLapplyLB, parRapply, parSapply, parSapplyLB

The following object is masked from ‘package:limma’:

    plotMA

The following objects are masked from ‘package:stats’:

    IQR, mad, xtabs

The following objects are masked from ‘package:base’:

    anyDuplicated, append, as.data.frame, cbind, colnames, do.call, duplicated, eval,
    evalq, Filter, Find, get, grep, grepl, intersect, is.unsorted, lapply, lengths,
    Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position,
    rank, rbind, Reduce, rownames, sapply, setdiff, sort, table, tapply, union, unique,
    unsplit, which, which.max, which.min

Loading required package: Biobase
Welcome to Bioconductor

    Vignettes contain introductory material; view with 'browseVignettes()'. To cite
    Bioconductor, see 'citation("Biobase")', and for packages 'citation("pkgname")'.

Loading required package: IRanges
Loading required package: S4Vectors

Attaching package: ‘S4Vectors’

The following objects are masked from ‘package:base’:

    colMeans, colSums, expand.grid, rowMeans, rowSums

First we need to decide what information we want. In order to see what we can extract we can run the columns function on the annotation database.

columns(org.Mm.eg.db)
 [1] "ACCNUM"       "ALIAS"        "ENSEMBL"      "ENSEMBLPROT"  "ENSEMBLTRANS"
 [6] "ENTREZID"     "ENZYME"       "EVIDENCE"     "EVIDENCEALL"  "GENENAME"    
[11] "GO"           "GOALL"        "IPI"          "MGI"          "ONTOLOGY"    
[16] "ONTOLOGYALL"  "PATH"         "PFAM"         "PMID"         "PROSITE"     
[21] "REFSEQ"       "SYMBOL"       "UNIGENE"      "UNIPROT"     

We are going to filter the database by a key or set of keys in order to extract the information we want. Valid names for the key can be retrieved with the keytypes function.

keytypes(org.Mm.eg.db)
 [1] "ACCNUM"       "ALIAS"        "ENSEMBL"      "ENSEMBLPROT"  "ENSEMBLTRANS" "ENTREZID"    
 [7] "ENZYME"       "EVIDENCE"     "EVIDENCEALL"  "GENENAME"     "GO"           "GOALL"       
[13] "IPI"          "MGI"          "ONTOLOGY"     "ONTOLOGYALL"  "PATH"         "PFAM"        
[19] "PMID"         "PROSITE"      "REFSEQ"       "SYMBOL"       "UNIGENE"      "UNIPROT"     

We should see ENTREZID, which is the type of key we are going to use in this case. If we are unsure what values are acceptable for the key, we can check what keys are valid with keys

keys(org.Mm.eg.db, keytype="ENTREZID")[1:10]
 [1] "11287" "11298" "11302" "11303" "11304" "11305" "11306" "11307" "11308" "11350"

It is a useful sanity check to make sure that the keys you want to use are all valid. We could use %in% in this case.

## Build up the query step-by-step
my.keys <- c("50916", "110308","12293")
my.keys %in% keys(org.Mm.eg.db, keytype="ENTREZID")
[1] TRUE TRUE TRUE
all(my.keys %in% keys(org.Mm.eg.db, keytype="ENTREZID"))
[1] TRUE

Let’s build up the query step by step.

## to be filled-in interactively during the class.
select(org.Mm.eg.db,

To annotate our results, we definitely want gene symbols and perhaps the full gene name. Let’s build up our annotation information in a separate data frame using the select function.

ann <- select(org.Mm.eg.db,keys=rownames(results),columns=c("ENTREZID","SYMBOL","GENENAME"))
'select()' returned 1:1 mapping between keys and columns
# Have a look at the annotation
ann

Let’s double check that the ENTREZID column matches exactly to our results rownames.

table(ann$ENTREZID==rownames(results))

 TRUE 
13309 

We can bind in the annotation information to the results data frame. (Please note that if the select function returns a 1:many mapping then you can’t just append the annotation to the fit object.)

results.annotated <- cbind(results, ann)
results.annotated

We can save the results table using the write.csv function, which writes the results out to a csv file that you can open in excel.

write.csv(results.annotated,file="B.PregVsLacResults.csv",row.names=FALSE)

A note about deciding how many genes are significant: In order to decide which genes are differentially expressed, we usually take a cut-off of 0.05 on the adjusted p-value, NOT the raw p-value. This is because we are testing more than 15000 genes, and the chances of finding differentially expressed genes is very high when you do that many tests. Hence we need to control the false discovery rate, which is the adjusted p-value column in the results table. What this means is that if 100 genes are significant at a 5% false discovery rate, we are willing to accept that 5 will be false positives. Note that the decideTests function displays significant genes at 5% FDR.

Challenge

Re-visit the plotSmear plot from above and use the text function to add labels for the names of the top 200 most DE genes

Another common visualisation is the volcano plot which display a measure of significance on the y-axis and fold-change on the x-axis.

signif <- -log10(results.annotated$FDR)
plot(results.annotated$logFC,signif,pch=16)
points(results.annotated[detags,"logFC"],-log10(results.annotated[detags,"FDR"]),pch=16,col="red")

Before following up on the DE genes with further lab work, a recommended sanity check is to have a look at the expression levels of the individual samples for the genes of interest. We can quickly look at grouped expression using stripchart. We can use the normalised log expression values in the dgeCounts object (dgeCounts$counts).

library(RColorBrewer)
par(mfrow=c(1,3))
normCounts <- dgeObj$counts
# Let's look at the first gene in the topTable, Irx4, which has a rowname 50916
stripchart(normCounts["50916",]~group)
# This plot is ugly, let's make it better
stripchart(normCounts["50916",]~group,vertical=TRUE,las=2,cex.axis=0.8,pch=16,col=1:6,method="jitter")
# Let's use nicer colours
nice.col <- brewer.pal(6,name="Dark2")
stripchart(normCounts["50916",]~group,vertical=TRUE,las=2,cex.axis=0.8,pch=16,cex=1.3,col=nice.col,method="jitter",ylab="Normalised log2 expression",main=" Irx4")

An interactive version of the volcano plot above that includes the raw per sample values in a separate panel is possible via the glXYPlot function in the Glimma package.

library(Glimma)
group2 <- group
levels(group2) <- c("basal.lactate","basal.preg","basal.virgin","lum.lactate", "lum.preg", "lum.virgin")
glXYPlot(x=results$logFC, y=-log10(results$FDR),
         xlab="logFC", ylab="B", main="B.PregVsLac",
         counts=normCounts, groups=group2, status=de,
         anno=ann, id.column="ENTREZID", folder="volcano")

This function creates an html page (./volcano/XY-Plot.html) with a volcano plot on the left and a plot showing the log-CPM per sample for a selected gene on the right. A search bar is available to search for genes of interest.

Retrieving Genomic Locations

It might seem natural to add genomic locations to our annotation table, and possibly a bit odd that the org.Mm.eg.db package does not supply such mappings. In fact, there is a whole suite of package for performing this, and more-advanced queries. These are listed on the Bioconductor annotation page and have the prefix TxDb.

The package we will be using is TxDb.Mmusculus.UCSC.mm10.knownGene. Packages are available for other organisms and genome builds. It is even possible to build your own database if one does not exist. See vignette("GenomicFeatures") for details

source("http://www.bioconductor.org/biocLite.R")
biocLite("TxDb.Mmusculus.UCSC.mm10.knownGene")

## For Humans
biocLite("TxDb.Hsapiens.UCSC.hg19.knownGene")

We load the library in the usual fashion and create a new object to save some typing. As with the org. packages, we can query what columns are available with columns,

library(TxDb.Mmusculus.UCSC.mm10.knownGene)
Loading required package: GenomicFeatures
Loading required package: GenomeInfoDb
Loading required package: GenomicRanges
tx <- TxDb.Mmusculus.UCSC.mm10.knownGene
columns(tx)
 [1] "CDSCHROM"   "CDSEND"     "CDSID"      "CDSNAME"    "CDSSTART"   "CDSSTRAND" 
 [7] "EXONCHROM"  "EXONEND"    "EXONID"     "EXONNAME"   "EXONRANK"   "EXONSTART" 
[13] "EXONSTRAND" "GENEID"     "TXCHROM"    "TXEND"      "TXID"       "TXNAME"    
[19] "TXSTART"    "TXSTRAND"   "TXTYPE"    

The select function is used in the same manner as the org.Mm.eg.db packages.

keys <- c("12992", "13358","20531")
select(tx, keys=keys,
       keytype = "GENEID",
       columns=c("EXONID","EXONSTART","EXONEND"))
'select()' returned 1:many mapping between keys and columns

One of the real strengths of the txdb.. packages is the ability of interface with GenomicRanges, which is the object type used throughout Bioconductor to manipulate Genomic Intervals.

These object types permit us to perform common operations on intervals such as overlapping and counting.

library(GenomicRanges)
my.range <-GRanges("chr1", IRanges(start=1000,end=2000))
my.range
GRanges object with 1 range and 0 metadata columns:
      seqnames       ranges strand
         <Rle>    <IRanges>  <Rle>
  [1]     chr1 [1000, 2000]      *
  -------
  seqinfo: 1 sequence from an unspecified genome; no seqlengths

Let’s try some dummy intervals with random chromsome assignments and start positions.

set.seed(10042017)
chrs <- sample(paste0("chr",1:19),100,replace=TRUE)
startPos <- sample(1:5e6,100,replace=TRUE)
my.rangesA <- GRanges(chrs, IRanges(start=startPos,width=1000))
my.rangesA
GRanges object with 100 ranges and 0 metadata columns:
        seqnames             ranges strand
           <Rle>          <IRanges>  <Rle>
    [1]    chr19 [1534111, 1535110]      *
    [2]    chr10 [4608224, 4609223]      *
    [3]     chr7 [2546454, 2547453]      *
    [4]     chr7 [3599137, 3600136]      *
    [5]    chr18 [ 895462,  896461]      *
    ...      ...                ...    ...
   [96]    chr12 [3244195, 3245194]      *
   [97]    chr11 [3320136, 3321135]      *
   [98]    chr11 [ 418010,  419009]      *
   [99]    chr12 [1351347, 1352346]      *
  [100]     chr3 [2710560, 2711559]      *
  -------
  seqinfo: 19 sequences from an unspecified genome; no seqlengths

There are a number of useful functions for calculating properties of the data (such as coverage or sorting). It is even possible to convert between different chromosome naming conventions.

width(my.rangesA)
  [1] 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
 [17] 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
 [33] 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
 [49] 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
 [65] 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
 [81] 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000
 [97] 1000 1000 1000 1000
sort(my.rangesA)
GRanges object with 100 ranges and 0 metadata columns:
        seqnames             ranges strand
           <Rle>          <IRanges>  <Rle>
    [1]    chr19 [ 496023,  497022]      *
    [2]    chr19 [1534111, 1535110]      *
    [3]    chr19 [2444002, 2445001]      *
    [4]    chr19 [3406152, 3407151]      *
    [5]    chr10 [  63660,   64659]      *
    ...      ...                ...    ...
   [96]     chr4 [4437249, 4438248]      *
   [97]     chr4 [4853087, 4854086]      *
   [98]     chr3 [2710560, 2711559]      *
   [99]     chr3 [2867165, 2868164]      *
  [100]    chr13 [2362583, 2363582]      *
  -------
  seqinfo: 19 sequences from an unspecified genome; no seqlengths
coverage(my.rangesA)
RleList of length 19
$chr19
integer-Rle of length 3407151 with 8 runs
  Lengths:  496022    1000 1037088    1000  908891    1000  961150    1000
  Values :       0       1       0       1       0       1       0       1

$chr10
integer-Rle of length 4609223 with 12 runs
  Lengths:   63659    1000 1012827    1000  959543 ...  860029    1000  405082    1000
  Values :       0       1       0       1       0 ...       0       1       0       1

$chr7
integer-Rle of length 4627728 with 16 runs
  Lengths:   63290    1000 1212862    1000  493363 ...  630989    1000 1026592    1000
  Values :       0       1       0       1       0 ...       0       1       0       1

$chr18
integer-Rle of length 4436160 with 14 runs
  Lengths:  160693    1000  396731    1000  336037 ... 1006023    1000   87480    1000
  Values :       0       1       0       1       0 ...       0       1       0       1

$chr11
integer-Rle of length 4755123 with 14 runs
  Lengths:  418009    1000  455255    1000  943607 ... 1307517    1000  124471    1000
  Values :       0       1       0       1       0 ...       0       1       0       1

...
<14 more elements>
seqlevelsStyle(my.rangesA)
[1] "UCSC"
keepSeqlevels(my.rangesA,"chr19")
GRanges object with 4 ranges and 0 metadata columns:
      seqnames             ranges strand
         <Rle>          <IRanges>  <Rle>
  [1]    chr19 [1534111, 1535110]      *
  [2]    chr19 [2444002, 2445001]      *
  [3]    chr19 [ 496023,  497022]      *
  [4]    chr19 [3406152, 3407151]      *
  -------
  seqinfo: 1 sequence from an unspecified genome; no seqlengths
#seqlevelsStyle(my.rangesA) <- "Ensembl"
#my.rangesA
my.rangesB <- shift(my.rangesA, shift = 500)
my.rangesB <- resize(my.rangesB,width =sample(1:1000,100,replace = TRUE))
my.rangesB
GRanges object with 100 ranges and 0 metadata columns:
        seqnames             ranges strand
           <Rle>          <IRanges>  <Rle>
    [1]    chr19 [1534611, 1535582]      *
    [2]    chr10 [4608724, 4609486]      *
    [3]     chr7 [2546954, 2546968]      *
    [4]     chr7 [3599637, 3599782]      *
    [5]    chr18 [ 895962,  896517]      *
    ...      ...                ...    ...
   [96]    chr12 [3244695, 3244941]      *
   [97]    chr11 [3320636, 3321524]      *
   [98]    chr11 [ 418510,  419236]      *
   [99]    chr12 [1351847, 1352549]      *
  [100]     chr3 [2711060, 2711736]      *
  -------
  seqinfo: 19 sequences from an unspecified genome; no seqlengths

It is quite straightforward to translate the output of a select query into a GenomicFeatures object. However, several convenience functions exist to retrieve the structure of every gene for a given organism in one object.

The output of exonsBy is a list, where each item in the list is the exon co-ordinates of a particular gene.

exo <- exonsBy(tx,"gene")
exo
GRangesList object of length 24116:
$100009600 
GRanges object with 7 ranges and 2 metadata columns:
      seqnames               ranges strand |   exon_id   exon_name
         <Rle>            <IRanges>  <Rle> | <integer> <character>
  [1]     chr9 [21062393, 21062717]      - |    134539        <NA>
  [2]     chr9 [21062894, 21062987]      - |    134540        <NA>
  [3]     chr9 [21063314, 21063396]      - |    134541        <NA>
  [4]     chr9 [21066024, 21066377]      - |    134542        <NA>
  [5]     chr9 [21066940, 21067925]      - |    134543        <NA>
  [6]     chr9 [21068030, 21068117]      - |    134544        <NA>
  [7]     chr9 [21073075, 21075496]      - |    134546        <NA>

$100009609 
GRanges object with 6 ranges and 2 metadata columns:
      seqnames               ranges strand | exon_id exon_name
  [1]     chr7 [84940169, 84941088]      - |  109989      <NA>
  [2]     chr7 [84943141, 84943264]      - |  109990      <NA>
  [3]     chr7 [84943504, 84943722]      - |  109991      <NA>
  [4]     chr7 [84946200, 84947000]      - |  109992      <NA>
  [5]     chr7 [84947372, 84947651]      - |  109993      <NA>
  [6]     chr7 [84963816, 84964009]      - |  109994      <NA>

$100009614 
GRanges object with 1 range and 2 metadata columns:
      seqnames               ranges strand | exon_id exon_name
  [1]    chr10 [77711446, 77712009]      + |  143986      <NA>

...
<24113 more elements>
-------
seqinfo: 66 sequences (1 circular) from mm10 genome

To access the structure of a particular gene, we can use the [[ syntax with the name of the gene (Entrez gene ID) within quote marks.

exo[["12992"]]
GRanges object with 14 ranges and 2 metadata columns:
       seqnames               ranges strand |   exon_id   exon_name
          <Rle>            <IRanges>  <Rle> | <integer> <character>
   [1]     chr5 [87808121, 87808165]      + |     68233        <NA>
   [2]     chr5 [87809897, 87809959]      + |     68234        <NA>
   [3]     chr5 [87813088, 87813114]      + |     68235        <NA>
   [4]     chr5 [87813838, 87813861]      + |     68236        <NA>
   [5]     chr5 [87813941, 87813982]      + |     68237        <NA>
   ...      ...                  ...    ... .       ...         ...
  [10]     chr5 [87819066, 87819095]      + |     68242        <NA>
  [11]     chr5 [87819066, 87819110]      + |     68243        <NA>
  [12]     chr5 [87820951, 87820995]      + |     68244        <NA>
  [13]     chr5 [87822212, 87822322]      + |     68245        <NA>
  [14]     chr5 [87824139, 87824421]      + |     68246        <NA>
  -------
  seqinfo: 66 sequences (1 circular) from mm10 genome

Exporting tracks

It is also possible to save the results of a Bioconductor analysis in a browser to enable interactive analysis and integration with other data types, or sharing with collaborators. For instance, we might want a browser track to indicate where our differentially-expressed genes are located. We shall use the bed format to display these locations.

At the moment, we have a GenomicFeatures object that represents every exon. However, we do not need this level of granularity for the bed output

Select the names of the statistically significant genes from the edgeR output in the usual manner.

tt <- topTable(fit.cont,coef="B.PregVsLac",n=Inf)
Error in is(fit, "MArrayLM") : object 'fit.cont' not found

Use the range function to obtain a single range for every gene and then get the genomic intervals that correspond to these DE genes.

exoRanges <- unlist(range(exo))
sigRegions <- exoRanges[na.omit(match(sigGenes$ENTREZID, names(exoRanges)))]
sigRegions

Rather than just representing the genomic locations, the .bed format is also able to colour each range according to some property of the analysis (e.g. direction and magnitude of change) to help highlight particular regions of interest. A score can also be displayed when a particular region is clicked-on. A useful propery of GenomicRanges is that we can attach metadata to each range using the mcols function. The metadata can be supplied in the form of a data frame.

mcols(sigRegions) <- sigGenes[match(names(sigRegions), sigGenes[,1]),]
sigRegions
seqlevels(sigRegions)
sigRegions <- keepSeqlevels(sigRegions, paste0("chr", c(1:19,"X","Y")))

Create a score from the p-values that will displayed under each region, and colour scheme for the regions based on the fold-change. For convenience, restrict the fold changes to be within the region -3 to 3.

sigRegions
Score <- -log10(sigRegions$adj.P.Val)
rbPal <-colorRampPalette(c("red", "blue"))
logfc <- pmax(sigRegions$logFC, -3)
logfc <- pmin(logfc , 3)
Col <- rbPal(10)[as.numeric(cut(logfc, breaks = 10))]

The colours and score can be saved in the GRanges object and score and itemRgb columns respectively and will be used to construct the track when exporting. The rtracklayer function can be used to import and export browsers tracks.

Export the signifcant results from the DE analysis as a .bed track using rtracklayer. You can load the resulting file in IGV, if you wish.

mcols(sigRegions)$score <- Score
mcols(sigRegions)$itemRgb <- Col
library(rtracklayer)
export(sigRegions , con = "topHits.bed")

Extracting Reads

We haven’t discussed much

library(GenomicAlignments)
generegion <- exo[["12992"]]
getwd()
bam <- readGAlignments(file="bam/MCL1.DG.bam",
                       param=ScanBamParam(which=generegion))
bam

An aside - Acessing Genome Sequence

Brief Introduction to ggplot2

library(ggplot2)

top200 <- tt[1:200,]

ggplot(tt, aes(x = logFC, y=B)) + geom_point(alpha=0.4) + scale_color_manual(values=c("black","red")) + geom_text(data=top200, aes(x=logFC,y=B,label=SYMBOL),col="blue",alpha=0.4)

Challenge

Use ggplot2 to re-construct the MA- plot from above.

Solution

Composing plots with ggbio

We will now take a brief look at one of the visualisation packages in Bioconductor that takes advantage of the GenomicRanges and GenomicFeatures object-types. In this section we will show a worked example of how to combine several types of genomic data on the same plot. The documentation for ggbio is very extensive and contains lots of examples.

http://www.tengfei.name/ggbio/docs/

The Gviz package is another Bioconductor package that specialising in genomic visualisations, but we will not explore this package in the course.

The Manhattan plot is a common way of visualising genome-wide results, and this is implemented as the plotGrandLinear function. We have to supply a value to display on the y-axis, typically this is some measure of significance. Changing this variable displayed on the y-axis is done by using the aes function, which is inherited from ggplot2. The positioning of points on the x-axis is handled automatically by ggbio, using the ranges information to get the genomic coordinates of the ranges of interest.

library(ggbio)
plotGrandLinear(sigRegions , aes(y = score))

As we discussed, an appealing feature of ggplot2 is the ability to map properties of your plot to variables present in your data. For example, we could create a variable to distinguish between up- and down-regulated genes. The variables used for aesthetic mapping must be present in the mcols section of your ranges object.

mcols(sigRegions)$Up <- logfc > 0
plotGrandLinear(sigRegions, aes(y = logFC, col = Up))

A useful function within ggbio is autoplot, which will construct an appropriate plot based on the object-type of the input. For example, ggbio is able to plot the structure of genes according to a particular model represented by a GenomicFeatures object.

autoplot(tx, which=exo[["24117"]])

We can even plot the location of sequencing reads if they have been imported using readGAlignments function (or similar).

myreg <- flank(reduce(exo[["24117"]]), 1000, both = T)
bam <- readGAlignments(file="bam/MCL1.DG.bam",
                       param=ScanBamParam(which=myreg),use.names = TRUE)

autoplot(bam,which=myreg)
autoplot(bam , stat = "coverage")

Like ggplot2, ggbio plots can be saved as objects that can later be modified, or combined together to form more complicated plots. If saved in this way, the plot will only be displayed on a plotting device when we query the object. This strategy is useful when we want to add a common element (such as an ideogram) to a plot composition and don’t want to repeat the code to generate the plot every time.

#idPlot <- plotIdeogram(genome = "mm10")
#idPlot
geneMod <- autoplot(tx, which = myreg)
Error: could not find function "autoplot"
LS0tCnRpdGxlOiAiUk5BLXNlcSBBbmFseXNpcyBpbiBSIgpzdWJ0aXRsZTogIkFubm90YXRpb24gYW5kIFZpc3VhbGlzYXRpb24gb2YgUk5BLXNlcSByZXN1bHRzIgphdXRob3I6ICJTdGVwaGFuZSBCYWxsZXJlYXUsIE1hcmsgRHVubmluZywgT3NjYXIgUnVlZGEsIEFzaGxleSBTYXdsZSIKZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiTGFzdCBtb2RpZmllZDogJWQgJWIgJVkiKWAnCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwptaW51dGVzOiAzMDAKbGF5b3V0OiBwYWdlCmJpYmxpb2dyYXBoeTogcmVmLmJpYgotLS0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgoqKk9yaWdpbmFsIEF1dGhvcnM6IEJlbGluZGEgUGhpcHNvbiwgQW5uYSBUcmlnb3MsIE1hdHQgUml0Y2hpZSwgTWFyaWEgRG95bGUsIEhhcnJpZXQgRGFzaG5vdywgQ2hhcml0eSBMYXcqKgpCYXNlZCBvbiB0aGUgY291cnNlIFtSTkFzZXEgYW5hbHlzaXMgaW4gUl0oaHR0cDovL2NvbWJpbmUtYXVzdHJhbGlhLmdpdGh1Yi5pby8yMDE2LTA1LTExLVJOQXNlcS8pIGRlbGl2ZXJlZCBvbiBNYXkgMTEvMTJ0aCAyMDE2CgpCZWZvcmUgc3RhcnRpbmcgdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIG1ha2Ugc3VyZSB3ZSBoYXZlIGFsbCB0aGUgcmVsZXZhbnQgb2JqZWN0cyBmcm9tIHRoZSBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBhbmFseXNpcyBwcmVzZW50LgoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGVkZ2VSKSkKbG9hZCgiUm9iamVjdHMvREUuUmRhdGEiKQpgYGAKCiMgT3ZlcnZpZXcKCi0gVmlzdWFsaXNpbmcgREUgcmVzdWx0cwotIEdldHRpbmcgYW5ub3RhdGlvbgotIFJldHJpZXZpbmcgZ2VuZSBtb2RlbHMKLSBFeHBvcnRpbmcgYnJvd3NlciB0cmFlY2tzCi0gVmlzdWFsaXNpbmcgcmVzdWx0cyB3aXRoIHJlc3BlY3QgdG8gZ2Vub21pYyBsb2NhdGlvbgoKIyMgQWRkaW5nIGFubm90YXRpb24gYW5kIHNhdmluZyB0aGUgcmVzdWx0cwoKV2UgaGF2ZSBhIGxpc3Qgb2Ygc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMsIGJ1dCB0aGUgb25seSBhbm5vdGF0aW9uIHdlIGNhbiBzZWUgaXMgdGhlIEVudHJleiBHZW5lIElELCB3aGljaCBpcyBub3QgdmVyeSBpbmZvcm1hdGl2ZS4gCmBgYHtyfQpyZXN1bHRzIDwtIGFzLmRhdGEuZnJhbWUodG9wVGFncyhscnQuQnZzTCxuID0gSW5mKSkKcmVzdWx0cwoKYGBgCgpgZWRnZVJgIHByb3ZpZGVzIGEgZnVuY3Rpb24gYHBsb3RTbWVhcmAgdGhhdCBhbGxvd3MgdXMgdG8gdmlzdWFsaXNlIHRoZSByZXN1bHRzIG9mIGEgREUgYW5hbHlzaXMuIEluIGEgc2ltaWxhciBtYW5uZXIgdG8gdGhlIFsqTUEtcGxvdCogZm9yIG1pY3JvYXJyYXkgZGF0YV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTUFfcGxvdCksIHRoaXMgcGxvdCBzaG93cyB0aGUgbG9nLWZvbGQgY2hhbmdlIGFnYWluc3QgbG9nLWNvdW50cyBwZXIgbWlsbGlvbiwgd2l0aCBERSBnZW5lcyBoaWdobGlnaHRlZDoKCmBgYHtyfQpzdW1tYXJ5KGRlIDwtIGRlY2lkZVRlc3RzREdFKGxydC5CdnNMKSkKZGV0YWdzIDwtIHJvd25hbWVzKGRnZU9iailbYXMubG9naWNhbChkZSldCnBsb3RTbWVhcihscnQuQnZzTCwgZGUudGFncz1kZXRhZ3MpCmBgYApIb3dldmVyLCBvbiBzdWNoIGEgcGxvdCBpdCB3b3VsZCBiZSBuaWNlIHRvIGFkZCBsYWJlbHMgdG8gaGlnaGxpZ2h0IHRoZSBnZW5lcyB3aXRoIG1vc3QgZXZpZGVuY2UgZm9yIGJlaW5nIERFLCBvciBvdXIgZmF2b3VyaXRlIGdlbmVzLiBUbyBwZXJmb3JtIHN1Y2ggYSB0YXNrIHdlIG5lZWQgdG8gbWFwIGJldHdlZW4gdGhlIGlkZW50aWZpZXJzIHdlIGhhdmUgaW4gdGhlIGBlZGdlUmAgb3V0cHV0IGFuZCBtb3JlIGZhbWlsaWFyIG5hbWVzLgoKVGhlcmUgYXJlIGEgbnVtYmVyIG9mIHdheXMgdG8gYWRkIGFubm90YXRpb24sIGJ1dCB3ZSB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0byBkbyB0aGlzIHVzaW5nIHRoZSAqb3JnLk1tLmVnLmRiKiBwYWNrYWdlLiBUaGlzIHBhY2thZ2UgaXMgb25lIG9mIHNldmVyYWwgKm9yZ2FuaXNtLWxldmVsKiBwYWNrYWdlcyB3aGljaCBhcmUgcmUtYnVpbHQgZXZlcnkgNiBtb250aHMuIFRoZXNlIHBhY2thZ2VzIGFyZSBsaXN0ZWQgb24gdGhlIFthbm5vdGF0aW9uIHNlY3Rpb25dKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvQmlvY1ZpZXdzLmh0bWwjX19fQW5ub3RhdGlvbkRhdGEpIG9mIHRoZSBCaW9jb25kdWN0b3IsIGFuZCBhcmUgaW5zdGFsbGVkIGluIHRoZSBzYW1lIHdheSBhcyByZWd1bGFyIEJpb2NvbmR1Y3RvciBwYWNrYWdlcy4gQW4gYWx0ZXJuYXRpdmUgYXBwcm9hY2ggaXMgdG8gdXNlIGBiaW9tYVJ0YCwgYW4gaW50ZXJmYWNlIHRvIHRoZSBbQmlvTWFydF0oaHR0cDovL3d3dy5iaW9tYXJ0Lm9yZy8pIHJlc291cmNlLiBCaW9NYXJ0IGlzIG11Y2ggbW9yZSBjb21wcmVoZW5zaXZlLCBidXQgdGhlIG9yZ2FuaXNtIHBhY2thZ2UgZml0IGJldHRlciBpbnRvIHRoZSBCaW9jb25kdWN0b3Igd29ya2Zsb3cuCgoKYGBge3IgZXZhbD1GQUxTRX0Kc291cmNlKCJodHRwOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvYmlvY0xpdGUuUiIpCmJpb2NMaXRlKCJvcmcuTW0uZWcuZGIiKQojIEZvciBIdW1hbgpiaW9jTGl0ZSgib3JnLkhzLmVnLmRiIikKYGBgCgpUaGUgcGFja2FnZXMgYXJlIGxhcmdlciBpbiBzaXplIHRoYXQgQmlvY29uZHVjdG9yIHNvZnR3YXJlIHBhY2FrZ2VzLCBidXQgZXNzZW50aWFsbHkgdGhleSBhcmUgZGF0YWJhc2VzIHRoYXQgY2FuIGJlIHVzZWQgdG8gbWFrZSAqb2ZmbGluZSogcXVlcmllcy4gCgpgYGB7cn0KbGlicmFyeShvcmcuTW0uZWcuZGIpCmBgYAoKCkZpcnN0IHdlIG5lZWQgdG8gZGVjaWRlIHdoYXQgaW5mb3JtYXRpb24gd2Ugd2FudC4gSW4gb3JkZXIgdG8gc2VlIHdoYXQgd2UgY2FuIGV4dHJhY3Qgd2UgY2FuIHJ1biB0aGUgYGNvbHVtbnNgIGZ1bmN0aW9uIG9uIHRoZSBhbm5vdGF0aW9uIGRhdGFiYXNlLgoKYGBge3J9CmNvbHVtbnMob3JnLk1tLmVnLmRiKQpgYGAKCldlIGFyZSBnb2luZyB0byBmaWx0ZXIgdGhlIGRhdGFiYXNlIGJ5IGEga2V5IG9yIHNldCBvZiBrZXlzIGluIG9yZGVyIHRvIGV4dHJhY3QgdGhlIGluZm9ybWF0aW9uIHdlIHdhbnQuIFZhbGlkIG5hbWVzIGZvciB0aGUga2V5IGNhbiBiZSByZXRyaWV2ZWQgd2l0aCB0aGUgYGtleXR5cGVzYCBmdW5jdGlvbi4KCmBgYHtyfQprZXl0eXBlcyhvcmcuTW0uZWcuZGIpCmBgYAoKV2Ugc2hvdWxkIHNlZSBgRU5UUkVaSURgLCB3aGljaCBpcyB0aGUgdHlwZSBvZiBrZXkgd2UgYXJlIGdvaW5nIHRvIHVzZSBpbiB0aGlzIGNhc2UuIElmIHdlIGFyZSB1bnN1cmUgd2hhdCB2YWx1ZXMgYXJlIGFjY2VwdGFibGUgZm9yIHRoZSBrZXksIHdlIGNhbiBjaGVjayB3aGF0IGtleXMgYXJlIHZhbGlkIHdpdGggYGtleXNgCgpgYGB7cn0Ka2V5cyhvcmcuTW0uZWcuZGIsIGtleXR5cGU9IkVOVFJFWklEIilbMToxMF0KYGBgCgpJdCBpcyBhIHVzZWZ1bCBzYW5pdHkgY2hlY2sgdG8gbWFrZSBzdXJlIHRoYXQgdGhlIGtleXMgeW91IHdhbnQgdG8gdXNlIGFyZSBhbGwgdmFsaWQuIFdlIGNvdWxkIHVzZSBgJWluJWAgaW4gdGhpcyBjYXNlLgoKYGBge3J9CiMjIEJ1aWxkIHVwIHRoZSBxdWVyeSBzdGVwLWJ5LXN0ZXAKbXkua2V5cyA8LSBjKCI1MDkxNiIsICIxMTAzMDgiLCIxMjI5MyIpCm15LmtleXMgJWluJSBrZXlzKG9yZy5NbS5lZy5kYiwga2V5dHlwZT0iRU5UUkVaSUQiKQphbGwobXkua2V5cyAlaW4lIGtleXMob3JnLk1tLmVnLmRiLCBrZXl0eXBlPSJFTlRSRVpJRCIpKQpgYGAKCkxldCdzIGJ1aWxkIHVwIHRoZSBxdWVyeSBzdGVwIGJ5IHN0ZXAuCgpgYGB7ciBldmFsPUZBTFNFfQojIyB0byBiZSBmaWxsZWQtaW4gaW50ZXJhY3RpdmVseSBkdXJpbmcgdGhlIGNsYXNzLgpzZWxlY3Qob3JnLk1tLmVnLmRiLAoKCmBgYAoKCgpUbyBhbm5vdGF0ZSBvdXIgcmVzdWx0cywgd2UgZGVmaW5pdGVseSB3YW50IGdlbmUgc3ltYm9scyBhbmQgcGVyaGFwcyB0aGUgZnVsbCBnZW5lIG5hbWUuIExldCdzIGJ1aWxkIHVwIG91ciBhbm5vdGF0aW9uIGluZm9ybWF0aW9uIGluIGEgc2VwYXJhdGUgZGF0YSBmcmFtZSB1c2luZyB0aGUgYHNlbGVjdGAgZnVuY3Rpb24uCgpgYGB7cn0KYW5uIDwtIHNlbGVjdChvcmcuTW0uZWcuZGIsa2V5cz1yb3duYW1lcyhyZXN1bHRzKSxjb2x1bW5zPWMoIkVOVFJFWklEIiwiU1lNQk9MIiwiR0VORU5BTUUiKSkKIyBIYXZlIGEgbG9vayBhdCB0aGUgYW5ub3RhdGlvbgphbm4KYGBgCgpMZXQncyBkb3VibGUgY2hlY2sgdGhhdCB0aGUgYEVOVFJFWklEYCBjb2x1bW4gbWF0Y2hlcyBleGFjdGx5IHRvIG91ciBgcmVzdWx0c2Agcm93bmFtZXMuCgpgYGB7cn0KdGFibGUoYW5uJEVOVFJFWklEPT1yb3duYW1lcyhyZXN1bHRzKSkKYGBgCgpXZSBjYW4gYmluZCBpbiB0aGUgYW5ub3RhdGlvbiBpbmZvcm1hdGlvbiB0byB0aGUgYHJlc3VsdHNgIGRhdGEgZnJhbWUuIChQbGVhc2Ugbm90ZSB0aGF0IGlmIHRoZSBgc2VsZWN0YCBmdW5jdGlvbiByZXR1cm5zIGEgMTptYW55IG1hcHBpbmcgdGhlbiB5b3UgY2FuJ3QganVzdCBhcHBlbmQgdGhlIGFubm90YXRpb24gdG8gdGhlIGZpdCBvYmplY3QuKQoKYGBge3J9CnJlc3VsdHMuYW5ub3RhdGVkIDwtIGNiaW5kKHJlc3VsdHMsIGFubikKcmVzdWx0cy5hbm5vdGF0ZWQKYGBgCgoKV2UgY2FuIHNhdmUgdGhlIHJlc3VsdHMgdGFibGUgdXNpbmcgdGhlIGB3cml0ZS5jc3ZgIGZ1bmN0aW9uLCB3aGljaCB3cml0ZXMgdGhlIHJlc3VsdHMgb3V0IHRvIGEgY3N2IGZpbGUgdGhhdCB5b3UgY2FuIG9wZW4gaW4gZXhjZWwuCgpgYGB7cn0Kd3JpdGUuY3N2KHJlc3VsdHMuYW5ub3RhdGVkLGZpbGU9IkIuUHJlZ1ZzTGFjUmVzdWx0cy5jc3YiLHJvdy5uYW1lcz1GQUxTRSkKYGBgCgoqKkEgbm90ZSBhYm91dCBkZWNpZGluZyBob3cgbWFueSBnZW5lcyBhcmUgc2lnbmlmaWNhbnQqKjogSW4gb3JkZXIgdG8gZGVjaWRlIHdoaWNoIGdlbmVzIGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQsIHdlIHVzdWFsbHkgdGFrZSBhIGN1dC1vZmYgb2YgMC4wNSBvbiB0aGUgYWRqdXN0ZWQgcC12YWx1ZSwgTk9UIHRoZSByYXcgcC12YWx1ZS4gVGhpcyBpcyBiZWNhdXNlIHdlIGFyZSB0ZXN0aW5nIG1vcmUgdGhhbiAxNTAwMCBnZW5lcywgYW5kIHRoZSBjaGFuY2VzIG9mIGZpbmRpbmcgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGlzIHZlcnkgaGlnaCB3aGVuIHlvdSBkbyB0aGF0IG1hbnkgdGVzdHMuIEhlbmNlIHdlIG5lZWQgdG8gY29udHJvbCB0aGUgZmFsc2UgZGlzY292ZXJ5IHJhdGUsIHdoaWNoIGlzIHRoZSBhZGp1c3RlZCBwLXZhbHVlIGNvbHVtbiBpbiB0aGUgcmVzdWx0cyB0YWJsZS4gV2hhdCB0aGlzIG1lYW5zIGlzIHRoYXQgaWYgMTAwIGdlbmVzIGFyZSBzaWduaWZpY2FudCBhdCBhIDVcJSBmYWxzZSBkaXNjb3ZlcnkgcmF0ZSwgd2UgYXJlIHdpbGxpbmcgdG8gYWNjZXB0IHRoYXQgNSB3aWxsIGJlIGZhbHNlIHBvc2l0aXZlcy4gTm90ZSB0aGF0IHRoZSBgZGVjaWRlVGVzdHNgIGZ1bmN0aW9uIGRpc3BsYXlzIHNpZ25pZmljYW50IGdlbmVzIGF0IDVcJSBGRFIuCgo+ICMjIENoYWxsZW5nZSB7LmNoYWxsZW5nZX0KPgo+IFJlLXZpc2l0IHRoZSBgcGxvdFNtZWFyYCBwbG90IGZyb20gYWJvdmUgYW5kIHVzZSB0aGUgYHRleHRgIGZ1bmN0aW9uIHRvIGFkZCBsYWJlbHMgZm9yIHRoZSBuYW1lcyBvZiB0aGUgdG9wIDIwMCBtb3N0IERFIGdlbmVzCj4KCmBgYHtyLGVjaG89RkFMU0UsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xMH0KCnBsb3RTbWVhcihscnQuQnZzTCwgZGUudGFncz1kZXRhZ3MpCgpOIDwtIDIwMAoKdGV4dChyZXN1bHRzLmFubm90YXRlZCRsb2dDUE1bMTpOXSxyZXN1bHRzLmFubm90YXRlZCRsb2dGQ1sxOk5dLGxhYmVscyA9IHJlc3VsdHMuYW5ub3RhdGVkJFNZTUJPTFsxOk5dLGNvbD0iYmx1ZSIpCmBgYAoKCkFub3RoZXIgY29tbW9uIHZpc3VhbGlzYXRpb24gaXMgdGhlIFsqdm9sY2FubyBwbG90Kl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVm9sY2Fub19wbG90XyhzdGF0aXN0aWNzKSkgd2hpY2ggZGlzcGxheSBhIG1lYXN1cmUgb2Ygc2lnbmlmaWNhbmNlIG9uIHRoZSB5LWF4aXMgYW5kIGZvbGQtY2hhbmdlIG9uIHRoZSB4LWF4aXMuIAoKYGBge3IsZmlnLmhlaWdodD01LGZpZy53aWR0aD0xMH0Kc2lnbmlmIDwtIC1sb2cxMChyZXN1bHRzLmFubm90YXRlZCRGRFIpCnBsb3QocmVzdWx0cy5hbm5vdGF0ZWQkbG9nRkMsc2lnbmlmLHBjaD0xNikKcG9pbnRzKHJlc3VsdHMuYW5ub3RhdGVkW2RldGFncywibG9nRkMiXSwtbG9nMTAocmVzdWx0cy5hbm5vdGF0ZWRbZGV0YWdzLCJGRFIiXSkscGNoPTE2LGNvbD0icmVkIikKCmBgYAoKCkJlZm9yZSBmb2xsb3dpbmcgdXAgb24gdGhlIERFIGdlbmVzIHdpdGggZnVydGhlciBsYWIgd29yaywgYSByZWNvbW1lbmRlZCAqc2FuaXR5IGNoZWNrKiBpcyB0byBoYXZlIGEgbG9vayBhdCB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgb2YgdGhlIGluZGl2aWR1YWwgc2FtcGxlcyBmb3IgdGhlIGdlbmVzIG9mIGludGVyZXN0LiBXZSBjYW4gcXVpY2tseSBsb29rIGF0IGdyb3VwZWQgZXhwcmVzc2lvbiB1c2luZyBgc3RyaXBjaGFydGAuIFdlIGNhbiB1c2UgdGhlIG5vcm1hbGlzZWQgbG9nIGV4cHJlc3Npb24gdmFsdWVzIGluIHRoZSAgYGRnZUNvdW50c2Agb2JqZWN0IChgZGdlQ291bnRzJGNvdW50c2ApLgoKYGBge3IsZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9NX0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCnBhcihtZnJvdz1jKDEsMykpCm5vcm1Db3VudHMgPC0gZGdlT2JqJGNvdW50cwojIExldCdzIGxvb2sgYXQgdGhlIGZpcnN0IGdlbmUgaW4gdGhlIHRvcFRhYmxlLCBJcng0LCB3aGljaCBoYXMgYSByb3duYW1lIDUwOTE2CnN0cmlwY2hhcnQobm9ybUNvdW50c1siNTA5MTYiLF1+Z3JvdXApCiMgVGhpcyBwbG90IGlzIHVnbHksIGxldCdzIG1ha2UgaXQgYmV0dGVyCnN0cmlwY2hhcnQobm9ybUNvdW50c1siNTA5MTYiLF1+Z3JvdXAsdmVydGljYWw9VFJVRSxsYXM9MixjZXguYXhpcz0wLjgscGNoPTE2LGNvbD0xOjYsbWV0aG9kPSJqaXR0ZXIiKQojIExldCdzIHVzZSBuaWNlciBjb2xvdXJzCm5pY2UuY29sIDwtIGJyZXdlci5wYWwoNixuYW1lPSJEYXJrMiIpCnN0cmlwY2hhcnQobm9ybUNvdW50c1siNTA5MTYiLF1+Z3JvdXAsdmVydGljYWw9VFJVRSxsYXM9MixjZXguYXhpcz0wLjgscGNoPTE2LGNleD0xLjMsY29sPW5pY2UuY29sLG1ldGhvZD0iaml0dGVyIix5bGFiPSJOb3JtYWxpc2VkIGxvZzIgZXhwcmVzc2lvbiIsbWFpbj0iCUlyeDQiKQpgYGAKCkFuIGludGVyYWN0aXZlIHZlcnNpb24gb2YgdGhlIHZvbGNhbm8gcGxvdCBhYm92ZSB0aGF0IGluY2x1ZGVzIHRoZSByYXcgcGVyIHNhbXBsZSB2YWx1ZXMgaW4gYSBzZXBhcmF0ZSBwYW5lbCBpcyBwb3NzaWJsZSB2aWEgdGhlIGBnbFhZUGxvdGAgZnVuY3Rpb24gaW4gdGhlICpHbGltbWEqIHBhY2thZ2UuCgoKYGBge3J9CmxpYnJhcnkoR2xpbW1hKQpncm91cDIgPC0gZ3JvdXAKbGV2ZWxzKGdyb3VwMikgPC0gYygiYmFzYWwubGFjdGF0ZSIsImJhc2FsLnByZWciLCJiYXNhbC52aXJnaW4iLCJsdW0ubGFjdGF0ZSIsICJsdW0ucHJlZyIsICJsdW0udmlyZ2luIikKZ2xYWVBsb3QoeD1yZXN1bHRzJGxvZ0ZDLCB5PS1sb2cxMChyZXN1bHRzJEZEUiksCiAgICAgICAgIHhsYWI9ImxvZ0ZDIiwgeWxhYj0iQiIsIG1haW49IkIuUHJlZ1ZzTGFjIiwKICAgICAgICAgY291bnRzPW5vcm1Db3VudHMsIGdyb3Vwcz1ncm91cDIsIHN0YXR1cz1kZSwKICAgICAgICAgYW5ubz1hbm4sIGlkLmNvbHVtbj0iRU5UUkVaSUQiLCBmb2xkZXI9InZvbGNhbm8iKQpgYGAKCgpUaGlzIGZ1bmN0aW9uIGNyZWF0ZXMgYW4gaHRtbCBwYWdlICguL3ZvbGNhbm8vWFktUGxvdC5odG1sKSB3aXRoIGEgdm9sY2FubyBwbG90IG9uIHRoZSBsZWZ0IGFuZCBhIHBsb3Qgc2hvd2luZyB0aGUgbG9nLUNQTSBwZXIgc2FtcGxlIGZvciBhIHNlbGVjdGVkIGdlbmUgb24gdGhlIHJpZ2h0LiBBIHNlYXJjaCBiYXIgaXMgYXZhaWxhYmxlIHRvIHNlYXJjaCBmb3IgZ2VuZXMgb2YgaW50ZXJlc3QuCgoKCiMjIFJldHJpZXZpbmcgR2Vub21pYyBMb2NhdGlvbnMKCgpJdCBtaWdodCBzZWVtIG5hdHVyYWwgdG8gYWRkIGdlbm9taWMgbG9jYXRpb25zIHRvIG91ciBhbm5vdGF0aW9uIHRhYmxlLCBhbmQgcG9zc2libHkgYSBiaXQgb2RkIHRoYXQgdGhlIGBvcmcuTW0uZWcuZGJgIHBhY2thZ2UgZG9lcyBub3Qgc3VwcGx5IHN1Y2ggbWFwcGluZ3MuIEluIGZhY3QsIHRoZXJlIGlzIGEgd2hvbGUgc3VpdGUgb2YgcGFja2FnZSBmb3IgcGVyZm9ybWluZyB0aGlzLCBhbmQgbW9yZS1hZHZhbmNlZCBxdWVyaWVzLiBUaGVzZSBhcmUgbGlzdGVkIG9uIHRoZSBCaW9jb25kdWN0b3IgW2Fubm90YXRpb24gcGFnZV0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9CaW9jVmlld3MuaHRtbCNfX19Bbm5vdGF0aW9uRGF0YSkgYW5kIGhhdmUgdGhlIHByZWZpeCBgVHhEYi5gCgpUaGUgcGFja2FnZSB3ZSB3aWxsIGJlIHVzaW5nIGlzIGBUeERiLk1tdXNjdWx1cy5VQ1NDLm1tMTAua25vd25HZW5lYC4gUGFja2FnZXMgYXJlIGF2YWlsYWJsZSBmb3Igb3RoZXIgb3JnYW5pc21zIGFuZCBnZW5vbWUgYnVpbGRzLiBJdCBpcyBldmVuIHBvc3NpYmxlIHRvICpidWlsZCB5b3VyIG93biBkYXRhYmFzZSogaWYgb25lIGRvZXMgbm90IGV4aXN0LiBTZWUgYHZpZ25ldHRlKCJHZW5vbWljRmVhdHVyZXMiKWAgZm9yIGRldGFpbHMKCmBgYHtyIGV2YWw9RkFMU0V9CnNvdXJjZSgiaHR0cDovL3d3dy5iaW9jb25kdWN0b3Iub3JnL2Jpb2NMaXRlLlIiKQpiaW9jTGl0ZSgiVHhEYi5NbXVzY3VsdXMuVUNTQy5tbTEwLmtub3duR2VuZSIpCgojIyBGb3IgSHVtYW5zCmJpb2NMaXRlKCJUeERiLkhzYXBpZW5zLlVDU0MuaGcxOS5rbm93bkdlbmUiKQoKYGBgCgpXZSBsb2FkIHRoZSBsaWJyYXJ5IGluIHRoZSB1c3VhbCBmYXNoaW9uIGFuZCBjcmVhdGUgYSBuZXcgb2JqZWN0IHRvIHNhdmUgc29tZSB0eXBpbmcuIEFzIHdpdGggdGhlIGBvcmcuYCBwYWNrYWdlcywgd2UgY2FuIHF1ZXJ5IHdoYXQgY29sdW1ucyBhcmUgYXZhaWxhYmxlIHdpdGggYGNvbHVtbnNgLAoKYGBge3J9CmxpYnJhcnkoVHhEYi5NbXVzY3VsdXMuVUNTQy5tbTEwLmtub3duR2VuZSkKdHggPC0gVHhEYi5NbXVzY3VsdXMuVUNTQy5tbTEwLmtub3duR2VuZQpjb2x1bW5zKHR4KQpgYGAKClRoZSBgc2VsZWN0YCBmdW5jdGlvbiBpcyB1c2VkIGluIHRoZSBzYW1lIG1hbm5lciBhcyB0aGUgYG9yZy5NbS5lZy5kYmAgcGFja2FnZXMuCgpgYGB7cn0Ka2V5cyA8LSBjKCIxMjk5MiIsICIxMzM1OCIsIjIwNTMxIikKc2VsZWN0KHR4LCBrZXlzPWtleXMsCiAgICAgICBrZXl0eXBlID0gIkdFTkVJRCIsCiAgICAgICBjb2x1bW5zPWMoIkVYT05JRCIsIkVYT05TVEFSVCIsIkVYT05FTkQiKSkKCmBgYAoKT25lIG9mIHRoZSByZWFsIHN0cmVuZ3RocyBvZiB0aGUgYHR4ZGIuLmAgcGFja2FnZXMgaXMgdGhlIGFiaWxpdHkgb2YgaW50ZXJmYWNlIHdpdGggYEdlbm9taWNSYW5nZXNgLCB3aGljaCBpcyB0aGUgb2JqZWN0IHR5cGUgdXNlZCB0aHJvdWdob3V0IEJpb2NvbmR1Y3RvciBbdG8gbWFuaXB1bGF0ZSBHZW5vbWljIEludGVydmFsc10oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wbWMvYXJ0aWNsZXMvUE1DMzczODQ1OC9wZGYvcGNiaS4xMDAzMTE4LnBkZikuIAoKVGhlc2Ugb2JqZWN0IHR5cGVzIHBlcm1pdCB1cyB0byBwZXJmb3JtIGNvbW1vbiBvcGVyYXRpb25zIG9uIGludGVydmFscyBzdWNoIGFzIG92ZXJsYXBwaW5nIGFuZCBjb3VudGluZy4KYGBge3J9CmxpYnJhcnkoR2Vub21pY1JhbmdlcykKbXkucmFuZ2UgPC1HUmFuZ2VzKCJjaHIxIiwgSVJhbmdlcyhzdGFydD0xMDAwLGVuZD0yMDAwKSkKbXkucmFuZ2UKCmBgYAoKTGV0J3MgdHJ5IHNvbWUgZHVtbXkgaW50ZXJ2YWxzIHdpdGggcmFuZG9tIGNocm9tc29tZSBhc3NpZ25tZW50cyBhbmQgc3RhcnQgcG9zaXRpb25zLiAKYGBge3J9CnNldC5zZWVkKDEwMDQyMDE3KQpjaHJzIDwtIHNhbXBsZShwYXN0ZTAoImNociIsMToxOSksMTAwLHJlcGxhY2U9VFJVRSkKc3RhcnRQb3MgPC0gc2FtcGxlKDE6NWU2LDEwMCxyZXBsYWNlPVRSVUUpCm15LnJhbmdlc0EgPC0gR1JhbmdlcyhjaHJzLCBJUmFuZ2VzKHN0YXJ0PXN0YXJ0UG9zLHdpZHRoPTEwMDApKQpteS5yYW5nZXNBCgpgYGAKClRoZXJlIGFyZSBhIG51bWJlciBvZiB1c2VmdWwgZnVuY3Rpb25zIGZvciBjYWxjdWxhdGluZyBwcm9wZXJ0aWVzIG9mIHRoZSBkYXRhIChzdWNoIGFzICpjb3ZlcmFnZSogb3Igc29ydGluZykuIEl0IGlzIGV2ZW4gcG9zc2libGUgdG8gY29udmVydCBiZXR3ZWVuIGRpZmZlcmVudCBjaHJvbW9zb21lIG5hbWluZyBjb252ZW50aW9ucy4KCmBgYHtyfQp3aWR0aChteS5yYW5nZXNBKQpzb3J0KG15LnJhbmdlc0EpCmNvdmVyYWdlKG15LnJhbmdlc0EpCnNlcWxldmVsc1N0eWxlKG15LnJhbmdlc0EpCmtlZXBTZXFsZXZlbHMobXkucmFuZ2VzQSwiY2hyMTkiKQojc2VxbGV2ZWxzU3R5bGUobXkucmFuZ2VzQSkgPC0gIkVuc2VtYmwiCiNteS5yYW5nZXNBCmBgYAoKCmBgYHtyfQpteS5yYW5nZXNCIDwtIHNoaWZ0KG15LnJhbmdlc0EsIHNoaWZ0ID0gNTAwKQpteS5yYW5nZXNCIDwtIHJlc2l6ZShteS5yYW5nZXNCLHdpZHRoID1zYW1wbGUoMToxMDAwLDEwMCxyZXBsYWNlID0gVFJVRSkpCm15LnJhbmdlc0IKYGBgCgpJdCBpcyBxdWl0ZSBzdHJhaWdodGZvcndhcmQgdG8gdHJhbnNsYXRlIHRoZSBvdXRwdXQgb2YgYSBgc2VsZWN0YCBxdWVyeSBpbnRvIGEgYEdlbm9taWNGZWF0dXJlc2Agb2JqZWN0LiBIb3dldmVyLCBzZXZlcmFsIGNvbnZlbmllbmNlIGZ1bmN0aW9ucyBleGlzdCB0byByZXRyaWV2ZSB0aGUgc3RydWN0dXJlIG9mIGV2ZXJ5IGdlbmUgZm9yIGEgZ2l2ZW4gb3JnYW5pc20gaW4gb25lIG9iamVjdC4gCgpUaGUgb3V0cHV0IG9mIGBleG9uc0J5YCBpcyBhIGxpc3QsIHdoZXJlIGVhY2ggaXRlbSBpbiB0aGUgbGlzdCBpcyB0aGUgZXhvbiBjby1vcmRpbmF0ZXMgb2YgYSBwYXJ0aWN1bGFyIGdlbmUuIAoKYGBge3J9CmV4byA8LSBleG9uc0J5KHR4LCJnZW5lIikKZXhvCmBgYAoKVG8gYWNjZXNzIHRoZSBzdHJ1Y3R1cmUgb2YgYSBwYXJ0aWN1bGFyIGdlbmUsIHdlIGNhbiB1c2UgdGhlIGBbW2Agc3ludGF4IHdpdGggdGhlIG5hbWUgb2YgdGhlIGdlbmUgKEVudHJleiBnZW5lIElEKSB3aXRoaW4gcXVvdGUgbWFya3MuCgpgYGB7cn0KZXhvW1siMTI5OTIiXV0KYGBgCgoKIyMgRXhwb3J0aW5nIHRyYWNrcwoKSXQgaXMgYWxzbyBwb3NzaWJsZSB0byBzYXZlIHRoZSByZXN1bHRzIG9mIGEgQmlvY29uZHVjdG9yIGFuYWx5c2lzIGluIGEgYnJvd3NlciB0byBlbmFibGUgaW50ZXJhY3RpdmUgYW5hbHlzaXMKYW5kIGludGVncmF0aW9uIHdpdGggb3RoZXIgZGF0YSB0eXBlcywgb3Igc2hhcmluZyB3aXRoIGNvbGxhYm9yYXRvcnMuIEZvciBpbnN0YW5jZSwgd2UgbWlnaHQgd2FudCBhCmJyb3dzZXIgdHJhY2sgdG8gaW5kaWNhdGUgd2hlcmUgb3VyIGRpZmZlcmVudGlhbGx5LWV4cHJlc3NlZCBnZW5lcyBhcmUgbG9jYXRlZC4gV2Ugc2hhbGwgdXNlIHRoZSBiZWQKZm9ybWF0IHRvIGRpc3BsYXkgdGhlc2UgbG9jYXRpb25zLgoKQXQgdGhlIG1vbWVudCwgd2UgaGF2ZSBhIEdlbm9taWNGZWF0dXJlcyBvYmplY3QgdGhhdCByZXByZXNlbnRzIGV2ZXJ5IGV4b24uIEhvd2V2ZXIsIHdlIGRvIG5vdApuZWVkIHRoaXMgbGV2ZWwgb2YgZ3JhbnVsYXJpdHkgZm9yIHRoZSBiZWQgb3V0cHV0CgpTZWxlY3QgdGhlIG5hbWVzIG9mIHRoZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGdlbmVzIGZyb20gdGhlIGVkZ2VSIG91dHB1dCBpbiB0aGUgdXN1YWwKbWFubmVyLgoKYGBge3J9CnR0IDwtIHRvcFRhYmxlKGZpdC5jb250LGNvZWY9IkIuUHJlZ1ZzTGFjIixuPUluZikKc2lnR2VuZXMgPC0gdHRbdHQkYWRqLlAuVmFsIDwgMC4wNSxdCnNpZ0dlbmVzCmBgYAoKVXNlIHRoZSBgcmFuZ2VgIGZ1bmN0aW9uIHRvIG9idGFpbiBhIHNpbmdsZSByYW5nZSBmb3IgZXZlcnkgZ2VuZSBhbmQgdGhlbiBnZXQgdGhlIGdlbm9taWMgaW50ZXJ2YWxzIHRoYXQgY29ycmVzcG9uZCB0byB0aGVzZSBERSBnZW5lcy4KCmBgYHtyfQpleG9SYW5nZXMgPC0gdW5saXN0KHJhbmdlKGV4bykpCnNpZ1JlZ2lvbnMgPC0gZXhvUmFuZ2VzW25hLm9taXQobWF0Y2goc2lnR2VuZXMkRU5UUkVaSUQsIG5hbWVzKGV4b1JhbmdlcykpKV0Kc2lnUmVnaW9ucwpgYGAKClJhdGhlciB0aGFuIGp1c3QgcmVwcmVzZW50aW5nIHRoZSBnZW5vbWljIGxvY2F0aW9ucywgdGhlIC5iZWQgZm9ybWF0IGlzIGFsc28gYWJsZSB0byBjb2xvdXIgZWFjaCByYW5nZQphY2NvcmRpbmcgdG8gc29tZSBwcm9wZXJ0eSBvZiB0aGUgYW5hbHlzaXMgKGUuZy4gZGlyZWN0aW9uIGFuZCBtYWduaXR1ZGUgb2YgY2hhbmdlKSB0byBoZWxwIGhpZ2hsaWdodApwYXJ0aWN1bGFyIHJlZ2lvbnMgb2YgaW50ZXJlc3QuIEEgc2NvcmUgY2FuIGFsc28gYmUgZGlzcGxheWVkIHdoZW4gYSBwYXJ0aWN1bGFyIHJlZ2lvbiBpcyBjbGlja2VkLW9uLgpBIHVzZWZ1bCBwcm9wZXJ5IG9mIEdlbm9taWNSYW5nZXMgaXMgdGhhdCB3ZSBjYW4gYXR0YWNoIG1ldGFkYXRhIHRvIGVhY2ggcmFuZ2UgdXNpbmcgdGhlIG1jb2xzCmZ1bmN0aW9uLiBUaGUgbWV0YWRhdGEgY2FuIGJlIHN1cHBsaWVkIGluIHRoZSBmb3JtIG9mIGEgZGF0YSBmcmFtZS4KCmBgYHtyfQptY29scyhzaWdSZWdpb25zKSA8LSBzaWdHZW5lc1ttYXRjaChuYW1lcyhzaWdSZWdpb25zKSwgc2lnR2VuZXNbLDFdKSxdCnNpZ1JlZ2lvbnMKYGBgCgpgYGB7cn0Kc2VxbGV2ZWxzKHNpZ1JlZ2lvbnMpCnNpZ1JlZ2lvbnMgPC0ga2VlcFNlcWxldmVscyhzaWdSZWdpb25zLCBwYXN0ZTAoImNociIsIGMoMToxOSwiWCIsIlkiKSkpCmBgYAoKQ3JlYXRlIGEgc2NvcmUgZnJvbSB0aGUgcC12YWx1ZXMgdGhhdCB3aWxsIGRpc3BsYXllZCB1bmRlciBlYWNoIHJlZ2lvbiwgYW5kIGNvbG91ciBzY2hlbWUKZm9yIHRoZSByZWdpb25zIGJhc2VkIG9uIHRoZSBmb2xkLWNoYW5nZS4gRm9yIGNvbnZlbmllbmNlLCByZXN0cmljdCB0aGUgZm9sZCBjaGFuZ2VzIHRvIGJlIHdpdGhpbiB0aGUKcmVnaW9uIC0zIHRvIDMuCgpgYGB7cn0Kc2lnUmVnaW9ucwpTY29yZSA8LSAtbG9nMTAoc2lnUmVnaW9ucyRhZGouUC5WYWwpCnJiUGFsIDwtY29sb3JSYW1wUGFsZXR0ZShjKCJyZWQiLCAiYmx1ZSIpKQpsb2dmYyA8LSBwbWF4KHNpZ1JlZ2lvbnMkbG9nRkMsIC0zKQpsb2dmYyA8LSBwbWluKGxvZ2ZjICwgMykKQ29sIDwtIHJiUGFsKDEwKVthcy5udW1lcmljKGN1dChsb2dmYywgYnJlYWtzID0gMTApKV0KYGBgCgpUaGUgY29sb3VycyBhbmQgc2NvcmUgY2FuIGJlIHNhdmVkIGluIHRoZSBHUmFuZ2VzIG9iamVjdCBhbmQgc2NvcmUgYW5kIGl0ZW1SZ2IgY29sdW1ucyByZXNwZWN0aXZlbHkKYW5kIHdpbGwgYmUgdXNlZCB0byBjb25zdHJ1Y3QgdGhlIHRyYWNrIHdoZW4gZXhwb3J0aW5nLiBUaGUgcnRyYWNrbGF5ZXIgZnVuY3Rpb24gY2FuIGJlIHVzZWQgdG8gaW1wb3J0CmFuZCBleHBvcnQgYnJvd3NlcnMgdHJhY2tzLgoKIEV4cG9ydCB0aGUgc2lnbmlmY2FudCByZXN1bHRzIGZyb20gdGhlIERFIGFuYWx5c2lzIGFzIGEgYC5iZWRgIHRyYWNrIHVzaW5nIGBydHJhY2tsYXllcmAuIFlvdQpjYW4gbG9hZCB0aGUgcmVzdWx0aW5nIGZpbGUgaW4gSUdWLCBpZiB5b3Ugd2lzaC4KYGBge3J9Cm1jb2xzKHNpZ1JlZ2lvbnMpJHNjb3JlIDwtIFNjb3JlCm1jb2xzKHNpZ1JlZ2lvbnMpJGl0ZW1SZ2IgPC0gQ29sCmxpYnJhcnkocnRyYWNrbGF5ZXIpCmV4cG9ydChzaWdSZWdpb25zICwgY29uID0gInRvcEhpdHMuYmVkIikKYGBgCgojIyBFeHRyYWN0aW5nIFJlYWRzCgpXZSBoYXZlbid0IGRpc2N1c3NlZCBtdWNoIAoKYGBge3J9CmxpYnJhcnkoR2Vub21pY0FsaWdubWVudHMpCmBgYAoKYGBge3J9CmdlbmVyZWdpb24gPC0gZXhvW1siMTI5OTIiXV0KZ2V0d2QoKQpiYW0gPC0gcmVhZEdBbGlnbm1lbnRzKGZpbGU9ImJhbS9NQ0wxLkRHLmJhbSIsCiAgICAgICAgICAgICAgICAgICAgICAgcGFyYW09U2NhbkJhbVBhcmFtKHdoaWNoPWdlbmVyZWdpb24pKQpiYW0KYGBgCgoKCiMjIEFuIGFzaWRlIC0gQWNlc3NpbmcgR2Vub21lIFNlcXVlbmNlCgpgYGB7cn0KCmBgYAoKIyMgQnJpZWYgSW50cm9kdWN0aW9uIHRvIGdncGxvdDIKCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQoKdG9wMjAwIDwtIHR0WzE6MjAwLF0KCmdncGxvdCh0dCwgYWVzKHggPSBsb2dGQywgeT1CKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwicmVkIikpICsgZ2VvbV90ZXh0KGRhdGE9dG9wMjAwLCBhZXMoeD1sb2dGQyx5PUIsbGFiZWw9U1lNQk9MKSxjb2w9ImJsdWUiLGFscGhhPTAuNCkKCmBgYAoKCj4gIyMgQ2hhbGxlbmdlIHsuY2hhbGxlbmdlfQo+Cj4gVXNlIGdncGxvdDIgdG8gcmUtY29uc3RydWN0IHRoZSBNQS0gcGxvdCBmcm9tIGFib3ZlLgo+CgoqKlNvbHV0aW9uKioKCmBgYHtyLGVjaG89RkFMU0V9CiMgU291dGlvbgp0dCA8LSB0b3BUYWJsZShmaXQuY29udCxjb2VmPSJCLlByZWdWc0xhYyIsbj1JbmYpCmdncGxvdCh0dCwgYWVzKHggPSBBdmVFeHByLCB5PWxvZ0ZDLGNvbD1hZGouUC5WYWwgPCAwLjA1KSkgKyBnZW9tX3BvaW50KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwicmVkIikpIAoKYGBgCgoKIyMgQ29tcG9zaW5nIHBsb3RzIHdpdGggZ2diaW8KCldlIHdpbGwgbm93IHRha2UgYSBicmllZiBsb29rIGF0IG9uZSBvZiB0aGUgdmlzdWFsaXNhdGlvbiBwYWNrYWdlcyBpbiBCaW9jb25kdWN0b3IgdGhhdCB0YWtlcyBhZHZhbnRhZ2UKb2YgdGhlIEdlbm9taWNSYW5nZXMgYW5kIEdlbm9taWNGZWF0dXJlcyBvYmplY3QtdHlwZXMuIEluIHRoaXMgc2VjdGlvbiB3ZSB3aWxsIHNob3cgYSB3b3JrZWQKZXhhbXBsZSBvZiBob3cgdG8gY29tYmluZSBzZXZlcmFsIHR5cGVzIG9mIGdlbm9taWMgZGF0YSBvbiB0aGUgc2FtZSBwbG90LiBUaGUgZG9jdW1lbnRhdGlvbiBmb3IKZ2diaW8gaXMgdmVyeSBleHRlbnNpdmUgYW5kIGNvbnRhaW5zIGxvdHMgb2YgZXhhbXBsZXMuCgpodHRwOi8vd3d3LnRlbmdmZWkubmFtZS9nZ2Jpby9kb2NzLwoKVGhlIEd2aXogcGFja2FnZSBpcyBhbm90aGVyIEJpb2NvbmR1Y3RvciBwYWNrYWdlIHRoYXQgc3BlY2lhbGlzaW5nIGluIGdlbm9taWMgdmlzdWFsaXNhdGlvbnMsIGJ1dCB3ZQp3aWxsIG5vdCBleHBsb3JlIHRoaXMgcGFja2FnZSBpbiB0aGUgY291cnNlLgoKVGhlIE1hbmhhdHRhbiBwbG90IGlzIGEgY29tbW9uIHdheSBvZiB2aXN1YWxpc2luZyBnZW5vbWUtd2lkZSByZXN1bHRzLCBhbmQgdGhpcyBpcyBpbXBsZW1lbnRlZCBhcyB0aGUKYHBsb3RHcmFuZExpbmVhcmAgZnVuY3Rpb24uIFdlIGhhdmUgdG8gc3VwcGx5IGEgdmFsdWUgdG8gZGlzcGxheSBvbiB0aGUgeS1heGlzLCB0eXBpY2FsbHkgdGhpcyBpcyBzb21lCm1lYXN1cmUgb2Ygc2lnbmlmaWNhbmNlLiBDaGFuZ2luZyB0aGlzIHZhcmlhYmxlIGRpc3BsYXllZCBvbiB0aGUgeS1heGlzIGlzIGRvbmUgYnkgdXNpbmcgdGhlIGBhZXNgIGZ1bmN0aW9uLAp3aGljaCBpcyBpbmhlcml0ZWQgZnJvbSBnZ3Bsb3QyLiBUaGUgcG9zaXRpb25pbmcgb2YgcG9pbnRzIG9uIHRoZSB4LWF4aXMgaXMgaGFuZGxlZCBhdXRvbWF0aWNhbGx5IGJ5CmdnYmlvLCB1c2luZyB0aGUgcmFuZ2VzIGluZm9ybWF0aW9uIHRvIGdldCB0aGUgZ2Vub21pYyBjb29yZGluYXRlcyBvZiB0aGUgcmFuZ2VzIG9mIGludGVyZXN0LgoKYGBge3J9CmxpYnJhcnkoZ2diaW8pCnBsb3RHcmFuZExpbmVhcihzaWdSZWdpb25zICwgYWVzKHkgPSBzY29yZSkpCgpgYGAKCkFzIHdlIGRpc2N1c3NlZCwgYW4gYXBwZWFsaW5nIGZlYXR1cmUgb2YgYGdncGxvdDJgIGlzIHRoZSBhYmlsaXR5IHRvIG1hcCBwcm9wZXJ0aWVzIG9mIHlvdXIgcGxvdCB0byB2YXJpYWJsZXMgcHJlc2VudCBpbiB5b3VyIGRhdGEuIEZvciBleGFtcGxlLCB3ZSBjb3VsZCBjcmVhdGUgYSB2YXJpYWJsZSB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIHVwLSBhbmQgZG93bi1yZWd1bGF0ZWQgZ2VuZXMuIFRoZSB2YXJpYWJsZXMgdXNlZCBmb3IgYWVzdGhldGljIG1hcHBpbmcgbXVzdCBiZSBwcmVzZW50IGluIHRoZSBgbWNvbHNgIHNlY3Rpb24gb2YgeW91ciByYW5nZXMgb2JqZWN0LgoKYGBge3J9Cm1jb2xzKHNpZ1JlZ2lvbnMpJFVwIDwtIGxvZ2ZjID4gMApwbG90R3JhbmRMaW5lYXIoc2lnUmVnaW9ucywgYWVzKHkgPSBsb2dGQywgY29sID0gVXApKQpgYGAKCgoKQSB1c2VmdWwgZnVuY3Rpb24gd2l0aGluIGdnYmlvIGlzIGBhdXRvcGxvdGAsIHdoaWNoIHdpbGwgY29uc3RydWN0IGFuIGFwcHJvcHJpYXRlIHBsb3QgYmFzZWQgb24gdGhlCm9iamVjdC10eXBlIG9mIHRoZSBpbnB1dC4gRm9yIGV4YW1wbGUsIGdnYmlvIGlzIGFibGUgdG8gcGxvdCB0aGUgc3RydWN0dXJlIG9mIGdlbmVzIGFjY29yZGluZyB0byBhCnBhcnRpY3VsYXIgbW9kZWwgcmVwcmVzZW50ZWQgYnkgYSBgR2Vub21pY0ZlYXR1cmVzYCBvYmplY3QuCgoKYGBge3J9CmF1dG9wbG90KHR4LCB3aGljaD1leG9bWyIyNDExNyJdXSkKYGBgCgpXZSBjYW4gZXZlbiBwbG90IHRoZSBsb2NhdGlvbiBvZiBzZXF1ZW5jaW5nIHJlYWRzIGlmIHRoZXkgaGF2ZSBiZWVuIGltcG9ydGVkIHVzaW5nIHJlYWRHQWxpZ25tZW50cwpmdW5jdGlvbiAob3Igc2ltaWxhcikuCgpgYGB7cn0KbXlyZWcgPC0gZmxhbmsocmVkdWNlKGV4b1tbIjI0MTE3Il1dKSwgMTAwMCwgYm90aCA9IFQpCmJhbSA8LSByZWFkR0FsaWdubWVudHMoZmlsZT0iYmFtL01DTDEuREcuYmFtIiwKICAgICAgICAgICAgICAgICAgICAgICBwYXJhbT1TY2FuQmFtUGFyYW0od2hpY2g9bXlyZWcpLHVzZS5uYW1lcyA9IFRSVUUpCgphdXRvcGxvdChiYW0sd2hpY2g9bXlyZWcpCmBgYAoKYGBge3J9CmF1dG9wbG90KGJhbSAsIHN0YXQgPSAiY292ZXJhZ2UiKQpgYGAKTGlrZSBnZ3Bsb3QyLCBnZ2JpbyBwbG90cyBjYW4gYmUgc2F2ZWQgYXMgb2JqZWN0cyB0aGF0IGNhbiBsYXRlciBiZSBtb2RpZmllZCwgb3IgY29tYmluZWQgdG9nZXRoZXIgdG8KZm9ybSBtb3JlIGNvbXBsaWNhdGVkIHBsb3RzLiBJZiBzYXZlZCBpbiB0aGlzIHdheSwgdGhlIHBsb3Qgd2lsbCBvbmx5IGJlIGRpc3BsYXllZCBvbiBhIHBsb3R0aW5nIGRldmljZQp3aGVuIHdlIHF1ZXJ5IHRoZSBvYmplY3QuIFRoaXMgc3RyYXRlZ3kgaXMgdXNlZnVsIHdoZW4gd2Ugd2FudCB0byBhZGQgYSBjb21tb24gZWxlbWVudCAoc3VjaCBhcwphbiBpZGVvZ3JhbSkgdG8gYSBwbG90IGNvbXBvc2l0aW9uIGFuZCBkb27igJl0IHdhbnQgdG8gcmVwZWF0IHRoZSBjb2RlIHRvIGdlbmVyYXRlIHRoZSBwbG90IGV2ZXJ5IHRpbWUuCgpgYGB7cn0KI2lkUGxvdCA8LSBwbG90SWRlb2dyYW0oZ2Vub21lID0gIm1tMTAiKQojaWRQbG90CmdlbmVNb2QgPC0gYXV0b3Bsb3QodHgsIHdoaWNoID0gbXlyZWcpCnJlYWRzMSA8LSBhdXRvcGxvdChiYW0sIHN0YXQgPSAiY292ZXJhZ2UiKQp0cmFja3MoZ2VuZU1vZCAscmVhZHMxKQpgYGAKCgo=